import { Component, OnDestroy, OnInit, ViewChild, EventEmitter } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { merge, of as observableOf } from 'rxjs';
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
import { Router } from '@angular/router';
import { MatDialog } from '@angular/material';
import { RestService } from '../services/rest.service';
import { TranslateService } from '@ngx-translate/core';
import { DepartmentDialogComponent } from './department-dialog/department-dialog.component';
import { DialogTypes, ActionTypes } from '../models/wdl-types';

import * as _ from 'lodash';

@Component({
  templateUrl: './department.component.html',
  styleUrls: ['./department.component.css'],
})
export class DepartmentComponent implements OnInit, OnDestroy {
  url = 'data/department';
  institution: any;
  user: any;
  displayedColumns: string[] = ['number', 'departmentName', 'actions'];
  dataSource = [];
  searchText = '';

  resultsLength = 0;
  pageSize = 25;
  isLoadingResults = true;

  search: EventEmitter<any> = new EventEmitter();

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor(public dialog: MatDialog,
              private router: Router,
              private translate: TranslateService,
              private rest: RestService) {
    this.institution = this.rest.getInstitution();
    if (!this.institution.id) {
      console.error('Instituion is invalid: ' + this.institution.id);
    }
    this.user = this.rest.getUser();
    if (!this.isUserQualified()) {
      this.displayedColumns = ['departmentName'];
    }
  }

  isUserQualified() {
    return this.user.role === 'admin';
  }

  refreshSearch() {
    this.paginator.pageIndex = 0;
    this.search.emit(this.searchText);
  }

  add() {
    this.dialog.open(DepartmentDialogComponent, {
      disableClose: false,
      autoFocus: false,
      width: '450px',
      data: {
        mode: ActionTypes.ADD,
        institution: this.institution
      }
    }).afterClosed().subscribe(data => {
      if (!data || _.isString(data)) {
        // action was aborted
        return;
      }

      this.rest.post(this.url, data).subscribe((resp) => {
        console.log('Department ' + data.departmentName + ' was added.');
        // link it to institution
        this.rest.link(this.url + '/' + resp['id'] + '/institution', 'data/institution/' + this.institution.id).subscribe(() => {
          this.refreshSearch();
        }, () => {
          console.error('Failed to link department to institution');
          this.refreshSearch();
        });
      }, message => {
        this.rest.showHttpError('addInstError', message);
      });
    });
  }

  modify(item) {
    this.dialog.open(DepartmentDialogComponent, {
      disableClose: false,
      autoFocus: false,
      width: '450px',
      data: {
        mode: ActionTypes.MODIFY,
        item: item,
        institution: this.institution
      }
    }).afterClosed().subscribe(data => {
      if (!data || _.isString(data)) {
        // action was aborted
        return;
      }

      this.rest.put(this.url + '/' + item.id, data).subscribe(() => {
        // Update all nurses with this department name
        this.rest.getWithParams('data/nurse/search/departmentName', {
          institutionId: this.institution.id,
          departmentName: item.departmentName
        }).subscribe(resp => {
          const nurses = resp['_embedded']['nurses'];
          nurses.forEach(nurse => {
            this.rest.patch('data/nurse/' + nurse.id, {
              departmentName: data.departmentName
            }).subscribe(() => {
              console.log('Nurse ' + nurse.nurseName + 'was updated with new department!');
            }, () => {
              console.warn('Nurse ' + nurse.nurseName + 'was NOT updated with new department!');
            })
          });
        });

        this.refreshSearch();
      }, message => {
        this.rest.showHttpError('addInstError', message);
      });
    });
  }

  remove(department) {
    // check if the department is linked to nurse
    this.rest.getWithParams('data/nurse/search/departmentName', {
      institutionId: this.institution.id,
      departmentName: department.departmentName
    }).subscribe(resp => {
      const nurses = resp['_embedded']['nurses'];
      if (nurses.length > 0) {
        const nonEmptyTitle = this.translate.get('deleteError')['value'];
        this.rest.openGenDialog(
          DialogTypes.ERROR,
          nonEmptyTitle,
          this.translate.get('nonEmptyDepartmentMessage', {personName: nurses[0]['nurseName']})['value'],
          null);
      } else {
        const title = this.translate.get('deleteConfirmation')['value'];
        const message = this.translate.get('deleteDepartmentMessage', {departmentName: department.departmentName})['value'];

        this.rest.openGenDialog(DialogTypes.CONFIRMATION, title, message, () => {
          this.rest.delete(this.url + '/' + department.id).subscribe(() => {
            this.refreshSearch();
          }, error => {
            this.rest.showHttpError(this.translate.get('error')['value'], error);
          });
        });
      }
    }, message => {
      console.error('Failed to get all nurses belong to department ' + department.departmentName);
    });
  }

  ngOnInit() {
    // If the user changes the sort order, reset back to the first page.
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page, this.search)
    .pipe(
      startWith({}),
      switchMap(() => {
        this.isLoadingResults = true;

        const params = {
          institutionId: this.institution.id,
          page: this.paginator.pageIndex ? this.paginator.pageIndex : 0,
          size: this.paginator.pageSize ? this.paginator.pageSize : this.pageSize
        };

        if (this.sort.active && this.sort.direction) {
          params['sort'] = this.sort.active + ',' + this.sort.direction
        }

        if (this.searchText) {
          params['name'] = this.searchText;
          return this.rest.getWithParams(this.url + '/search/name', params);
        } else {
          return this.rest.getWithParams(this.url + '/search/all', params);
        }
      }),
      map(data => {
        this.isLoadingResults = false;
        this.resultsLength = data['page']['totalElements'];

        let number = this.paginator.pageIndex * this.paginator.pageSize;
        const items = data['_embedded']['departments'];
        items.forEach(item => {
          item['number'] = ++number;
        });

        return items;
      }),
      catchError(() => {
        this.isLoadingResults = false;
        return observableOf([]);
      })
    ).subscribe(data => this.dataSource = data);
  }

  ngOnDestroy() {
  }
}
